/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "xpm_ownerid_test.h"

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>

#include "code_sign_utils.h"
#include "file_ex.h"
#include "xpm_common.h"

using namespace std;
using namespace std::chrono;
using namespace testing;
using namespace testing::ext;

namespace OHOS {
namespace Security {
namespace XpmUnitTest {
using namespace OHOS::Security::CodeSign;
static int g_systemFd, g_sharedFd, g_compatFd, g_debugFd, g_appFd1, g_appFd2;
static const std::string APP_BASE_PATH = "/data/app/el1/bundle/public/tmp";
static const std::string SharedOwnerIDHAPPath =  APP_BASE_PATH + "/demo_ownerid/hap1-shared-lib-id.hap";
static const std::string WOOwnerIDHAPPath     =  APP_BASE_PATH + "/demo_ownerid/hap2-without-ownerid.hap";
static const std::string DebugOwnerIDPath     =  APP_BASE_PATH + "/demo_ownerid/hap3-debug-lib-id.hap";
static const std::string OwnerID1HAPPath      =  APP_BASE_PATH + "/demo_ownerid/hap4-ownerid-1.hap";
static const std::string OwnerID2HAPPath      =  APP_BASE_PATH + "/demo_ownerid/hap5-ownerid-2.hap";

void XpmOwnerIDTest::SetUpTestCase()
{
    SaveStringToFile(SELINUX_MODE_PATH, PERMISSIVE_MODE);
    SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, ENFORCE_MODE);

    EntryMap entryMap1;
    int ret = CodeSignUtils::EnforceCodeSignForAppWithOwnerId("SHARED_LIB_ID", SharedOwnerIDHAPPath, entryMap1, FILE_SELF);
    EXPECT_EQ(ret, CS_SUCCESS);

    EntryMap entryMap2;
    ret = CodeSignUtils::EnforceCodeSignForApp(WOOwnerIDHAPPath, entryMap2, FILE_SELF);
    EXPECT_EQ(ret, CS_SUCCESS);

    EntryMap entryMap3;
    ret = CodeSignUtils::EnforceCodeSignForAppWithOwnerId("DEBUG_LIB_ID", DebugOwnerIDPath, entryMap3, FILE_SELF);
    EXPECT_EQ(ret, CS_SUCCESS);

    EntryMap entryMap4;
    ret = CodeSignUtils::EnforceCodeSignForAppWithOwnerId("1234567890", OwnerID1HAPPath, entryMap4, FILE_SELF);
    EXPECT_EQ(ret, CS_SUCCESS);

    EntryMap entryMap5;
    ret = CodeSignUtils::EnforceCodeSignForAppWithOwnerId("12345678901", OwnerID2HAPPath, entryMap5, FILE_SELF);
    EXPECT_EQ(ret, CS_SUCCESS);

    g_systemFd = open(XPM_LIB_PATH.c_str(), O_RDONLY);
    EXPECT_NE(g_systemFd, -1);
    g_sharedFd = open(SharedOwnerIDHAPPath.c_str(), O_RDONLY);
    EXPECT_NE(g_sharedFd, -1);
    g_compatFd = open(WOOwnerIDHAPPath.c_str(), O_RDONLY);
    EXPECT_NE(g_compatFd, -1);
    g_debugFd = open(DebugOwnerIDPath.c_str(), O_RDONLY);
    EXPECT_NE(g_debugFd, -1);
    g_appFd1 = open(OwnerID1HAPPath.c_str(), O_RDONLY);
    EXPECT_NE(g_appFd1, -1);
    g_appFd2 = open(OwnerID2HAPPath.c_str(), O_RDONLY);
    EXPECT_NE(g_appFd2, -1);
}

void XpmOwnerIDTest::TearDownTestCase()
{
    close(g_systemFd);
    close(g_sharedFd);
    close(g_compatFd);
    close(g_debugFd);
    close(g_appFd1);
    close(g_appFd2);
    SaveStringToFile(XPM_DEBUG_FS_MODE_PATH, PERMISSIVE_MODE);
    SaveStringToFile(SELINUX_MODE_PATH, ENFORCE_MODE);
}

void XpmOwnerIDTest::SetUp()
{
}

void XpmOwnerIDTest::TearDown()
{
}

#define FILE_MAP_SIZE 40

/**
 * @tc.number 39.system进程打开所有文件
 * @tc.name: SystemProcess
 * @tc.desc:
 * @tc.result: SystemProcess
 */
HWTEST_F(XpmOwnerIDTest, SystemProcessTest, TestSize.Level0)
{
    // 设置当前进程为system进程
    SetXpmOwnerId(PROCESS_OWNERID_SYSTEM, NULL);

    // 1. LIB_SYSTEM_ID可以加载
    void *addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_systemFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 2. SHARED_LIB_ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_sharedFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 3. w/o Owner ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_compatFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 4. DEBUG_LIB_ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_debugFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 5. owner ID A的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd1, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 6. owner ID B的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd2, 0);
    EXPECT_EQ(MAP_FAILED, addr);
}

/**
 * @tc.number 40. Debug进程
 * @tc.name: DebugProcess
 * @tc.desc:
 * @tc.result: DebugProcess
 */
HWTEST_F(XpmOwnerIDTest, DebugProcessTest, TestSize.Level0)
{
    // 设置当前进程为debug进程
    SetXpmOwnerId(PROCESS_OWNERID_DEBUG, NULL);

    // 1. LIB_SYSTEM_ID可以加载
    void *addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_systemFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 2. SHARED_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_sharedFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 3. w/o Owner ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_compatFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 4. DEBUG_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_debugFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 5. owner ID A的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd1, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 6. owner ID B的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd2, 0);
    EXPECT_EQ(MAP_FAILED, addr);
}

/**
 * @tc.number 41. APPID进程
 * @tc.name: APPID Process
 * @tc.desc:
 * @tc.result: APPID Process
 */
HWTEST_F(XpmOwnerIDTest, APPProcessTest, TestSize.Level0)
{
    std::string str = "1234567890";
    // 设置当前进程为s进程
    SetXpmOwnerId(PROCESS_OWNERID_APP, str.c_str());

    // 1. LIB_SYSTEM_ID可以加载
    void *addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_systemFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 2. SHARED_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_sharedFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 3. w/o Owner ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_compatFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 4. DEBUG_LIB_ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_debugFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 5. owner ID A的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd1, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 6. owner ID B的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd2, 0);
    EXPECT_EQ(MAP_FAILED, addr);
}

/**
 * @tc.number 42.COMPAT进程
 * @tc.name: COMPAT Process
 * @tc.desc:
 * @tc.result: COMPAT Process
 */
HWTEST_F(XpmOwnerIDTest, COMPATProcessTest, TestSize.Level0)
{
    // 设置当前进程为COMPAT进程
    SetXpmOwnerId(PROCESS_OWNERID_COMPAT, NULL);

    // 1. LIB_SYSTEM_ID可以加载
    void *addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_systemFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 2. SHARED_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_sharedFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 3. w/o Owner ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_compatFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 4. DEBUG_LIB_ID的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_debugFd, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 5. owner ID A的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd1, 0);
    EXPECT_EQ(MAP_FAILED, addr);

    // 6. owner ID B的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd2, 0);
    EXPECT_EQ(MAP_FAILED, addr);
}

/**
 * @tc.number 43. EXTEND进程
 * @tc.name: EXTEND Process
 * @tc.desc:
 * @tc.result: EXTEND
 */
HWTEST_F(XpmOwnerIDTest, EXTENDProcessTest, TestSize.Level0)
{
    // 设置当前进程为s进程
    SetXpmOwnerId(PROCESS_OWNERID_EXTEND, NULL);

    // 1. LIB_SYSTEM_ID可以加载
    void *addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ | PROT_EXEC, MAP_PRIVATE, g_systemFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 2. SHARED_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_sharedFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 3. w/o Owner ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_compatFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 4. DEBUG_LIB_ID的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_debugFd, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 5. owner ID A的文件不可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd1, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);

    // 6. owner ID B的文件可以加载
    addr = mmap(NULL, FILE_MAP_SIZE, PROT_READ, MAP_PRIVATE | MAP_XPM, g_appFd2, 0);
    EXPECT_NE(MAP_FAILED, addr);
    munmap(addr, FILE_MAP_SIZE);
}

} // namespace XpmUnitTest
} // namespace Security
} // namespace OHOS